﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Pavilion;

namespace Pavilion.Control
{
    public class RootControl
    {
        static private RootControl singletonInstance;

        private Control topMostControl;
        private EditDisplay editDisplay;
        private Panel panel;

        public event Action<GameTime> UpdateLogic;

        private RootControl() : base()
        {
            singletonInstance = this;

            LoadInput();
            panel = new Panel(new Rectangle(0, 0, GameEngine.WindowWidth, GameEngine.WindowHeight));
            panel.BackgroundColor = Color.Transparent;
            editDisplay = new EditDisplay();
            editDisplay.MinimumHeight = 0;
            editDisplay.ContainsScroller = true;

            MouseCursor.MouseMoved += new Action<MouseCursor>(GameComponent_MouseMoved);
            editDisplay.Input.OuterClick += new Action<MouseCursor>(EditDisplay_OuterClick);

            panel.Collection.Added += (Control item, int index) => { item.IsActiveChanged += new Action<bool>(Control_IsActiveChanged); };
            panel.Collection.Removed += (Control item, int index) => { item.IsActiveChanged -= new Action<bool>(Control_IsActiveChanged); };
        }

        private void LoadInput()
        {
            MouseCursor = new PlayerMouse();
            Keyboard = new PlayerKeyboard();

            MouseCursor.Initialize(0.8f, 250, 250, 280, 190);
        }

        public void Clear()
        {
            panel.Collection.Clear();
        }

        static public RootControl Instance
        {
            get
            {
                if (singletonInstance == null)
                    new RootControl();

                return singletonInstance;
            }
        }

        public void Update(GameTime gameTime)
        {
            MouseCursor.Update(gameTime);
            Keyboard.Update(gameTime);

            OnUpdateLogic(gameTime);
        }

        public void Draw()
        {
            panel.Draw();
        }

        public void DisplayProperties(object[] objectList)
        {
            editDisplay.Clear();
            editDisplay.AddRange(objectList);

            editDisplay.Position = new Point(Mouse.GetState().X, Mouse.GetState().Y);
            Collection.Add(editDisplay);
        }

        private void UpdateTopMostControl()
        {
            Control control;
            Control previousControl = topMostControl;

            control = panel;

            //Finds the outmost Control over which the Mouse Cursor is over.
            while (control != null)
            {
                topMostControl = control;
                control = topMostControl.OuterMostControl(RootControl.Instance.MouseCursor);
            }

            //Checks if the mouse has left its previous territory and entered a new one.
            if (previousControl != topMostControl)
            {
                if (previousControl != null)
                    previousControl.Input.OnLeave();

                topMostControl.Input.OnEnter();
            }
        }

        /// <summary>
        /// Gets the collection component of this root control.
        /// </summary>
        public NotifiableCollection<Control> Collection
        {
            get { return panel.Collection; }
        }

        public MouseCursor MouseCursor { get; private set; }

        public IKeyboard Keyboard { get; private set; }

        private void OnUpdateLogic(GameTime gameTime)
        {
            if (UpdateLogic != null)
                UpdateLogic(gameTime);
        }

        private void GameComponent_MouseMoved(MouseCursor mouseCursor)
        {
            UpdateTopMostControl();
        }

        private void EditDisplay_OuterClick(MouseCursor mouseCursor)
        {
            editDisplay.DetachFromParent();
        }

        private void Control_IsActiveChanged(bool value)
        {
            UpdateTopMostControl();
        }
    }
}
